﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TileMap
{
    /// <summary>
    /// 标准WGS84计算瓦片，适用于google
    /// </summary>
    class MapPosCalc
    {
        /// <summary>
        /// 经纬度转墨卡托
        /// </summary>
        /// <param name="lonLat"></param>
        /// <returns></returns>
        static public Coordinate LonLat2Mercator(Coordinate lonLat)
        {
            Coordinate mercator = new Coordinate();
            double x = lonLat.Lon * 20037508.34 / 180;
            double y = Math.Log(Math.Tan((90 + lonLat.Lat) * Math.PI / 360)) / (Math.PI / 180);
            y = y * 20037508.34 / 180;
            mercator.Lon = x;
            mercator.Lat = y;

            return mercator;
        }

        /// <summary>
        /// 墨卡托转经纬度
        /// </summary>
        /// <param name="mercator"></param>
        /// <returns></returns>
        static public Coordinate Mercator2lonLat(Coordinate mercator)
        {
            Coordinate lonLat = new Coordinate();
            double x = mercator.Lon / 20037508.34 * 180;
            double y = mercator.Lat / 20037508.34 * 180;
            y = 180 / Math.PI * (2 * Math.Atan(Math.Exp(y * Math.PI / 180)) - Math.PI / 2);
            lonLat.Lon = x;
            lonLat.Lat = y;
            return lonLat;
        }

        /// <summary>
        /// 经纬度转瓦片索引
        /// 转换腾讯地图时，腾讯使用的坐标原点在左下，本计算公式返输入的经纬度的纬度需要正负翻转
        /// </summary>
        /// <param name="c">经纬度</param>
        /// <param name="zoom">缩放等级</param>
        /// <returns></returns>
        static public Point WorldToTilePos(Coordinate c, int zoom)
        {
            Point p = new Point
            {
                X = (int)Math.Floor((c.Lon + 180.0) / 360.0 * (1 << zoom)),
                Y = (int)Math.Floor((1.0 - Math.Log(Math.Tan(c.Lat * Math.PI / 180.0) +
                1.0 / Math.Cos(c.Lat * Math.PI / 180.0)) / Math.PI) / 2.0 * (1 << zoom))
            };

            return p;
        }

        /// <summary>
        /// 瓦片索引转经纬度
        /// 转换腾讯地图时，腾讯使用的坐标原点在左下，本计算公式返回的坐标纬度正负颠倒
        /// </summary>
        /// <param name="tile"></param>
        /// <param name="zoom"></param>
        /// <returns></returns>
        static public Coordinate TileToWorldPos(Point tile, int zoom)
        {
            Coordinate c = new Coordinate();
            double n = Math.PI - ((2.0 * Math.PI * tile.Y) / Math.Pow(2.0, zoom));

            c.Lon = (tile.X / Math.Pow(2.0, zoom) * 360.0) - 180.0;
            c.Lat = 180.0 / Math.PI * Math.Atan(Math.Sinh(n));

            return c;
        }
    }
}
